﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;

namespace loveMotorcade.web.Classes
{
    /// <summary>
    /// 文件上传及图片和它的缩略图处理
    /// </summary>
    public class myUpload
    {
        /// <summary>
        /// 可访问路径:从Web.config中取得 "/content/upload"
        /// </summary>
        string showPath { get; set; }

        /// <summary>
        /// 隐藏路径: 从Web.config中取得 "/upload"
        /// </summary>
        string hidePath { get; set; }

        /// <summary>
        /// 上传目录 注意前不要加"/" 后加"/" 默认为空
        /// </summary>
        public string myDirectory { get; set; }
        /// <summary>
        /// 指定图片压缩率
        /// </summary>
        public long compressLevel = 90;

        /// <summary>
        /// 文件类型验证 “|”分割,不区分大小写 留空则可以全部上传
        /// </summary>
        public string fileExts { get; set; }

        /// <summary>
        /// 是否可以通过url访问 默认为true
        /// </summary>
        public bool visibility { get; set; }
        /// <summary>
        /// 图片文件时，保持的最大长宽
        /// 默认为空
        /// </summary>
        public string imageResize { get; set; }
        /// <summary>
        /// 缩略图尺寸 默认为 "180*120"
        /// </summary>
        public string thumbnailSize { get; set; }

        /// <summary>
        /// 缩略图生成方式 
        /// "pHW":按照比例缩放(默认值) 
        ///  "HW":变形缩放 
        ///   "W":指定宽，高按比例 
        ///   "H":指定高，宽按比例 
        /// "Cut":指定高宽裁减（不变形）  
        /// </summary>
        public string thumbnailMode { get; set; }

        /// <summary>
        /// 存储时是否改名
        /// 默认为 true 改名 
        /// </summary>
        public bool reFilename { get; set; }

        private int thumbnailwidth;
        private int thumbnailheight;

        public myUpload()
        {

            showPath = System.Configuration.ConfigurationManager.AppSettings["showUpfilePathRoot"];
            if (showPath == null) showPath = "content/upload/";

            hidePath = System.Configuration.ConfigurationManager.AppSettings["hideUpfilePathRoot"];
            if (hidePath == null) hidePath = "uploads/";

            fileExts = "";
            myDirectory = "";
            visibility = true;
            thumbnailSize = "180*120";
            getWH(thumbnailSize);

            thumbnailMode = "H";
            reFilename = true;
        }

        /// <summary>
        /// 存储文件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public string save(HttpPostedFileBase file)
        {
            if (!fileValidate(file)) return "error|文件大小或类型错误!";

            //创建目录及文件名
            string pathBase = (visibility ? showPath : hidePath) + myDirectory;
            var path = createPath(pathBase);
            var fileName = reFilename ? makeFileName() + Path.GetExtension(file.FileName).ToLower() : Path.GetFileName(file.FileName).ToLower();

            try
            {
                file.SaveAs(Path.Combine(path, fileName));
            }
            catch
            {
                return "error|文件创建失败!";
            }
            return @"ok|/" + pathBase + fileName;

        }

        /// <summary>
        /// 存储多个文件
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        public string[] save(HttpFileCollectionBase files)
        {
            myUpload myfile = new myUpload();
            myfile = this;

            string[] reInfo = new string[files.Count];

            for (int i = 0; i < files.Count; i++)
            {
                reInfo[i] = myfile.save(files[i]);

            }
            return reInfo;
        }

        /// <summary>
        /// 存储文件，返回逗号分隔的路径
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        public string saveFiles(HttpFileCollectionBase files)
        {
            ArrayList re = new ArrayList();
            foreach (string item in save(files))
            {
                string[] temp = item.Split('|');
                if (temp[0] == "ok") re.Add(temp[1]);
            }
            return string.Join(",", (String[])re.ToArray(typeof(string)));
        }


        /// <summary>
        /// 单一图片文件带缩略图存储
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public string imageSave(HttpPostedFileBase file,Boolean compress = false)
        {
            if (!fileValidate(file)) return "error|文件大小或类型错误!";
            if (Path.GetExtension(file.FileName).ToLower() != ".jpg" && Path.GetExtension(file.FileName).ToLower() != ".gif" && Path.GetExtension(file.FileName).ToLower() != ".png") return "error|文件不是图片!";

            //创建目录及文件名
            string pathBase = (visibility ? showPath : hidePath) + myDirectory;
            var path = createPath(pathBase);
            //var fileName = makeFileName() + Path.GetExtension(file.FileName).ToLower();
            var fileName = reFilename ? makeFileName() + Path.GetExtension(file.FileName).ToLower() : Path.GetFileName(file.FileName).ToLower();

            

            //上传文件
            try
            {
                //改变大小压缩
                if (compress ) {
                    Image img = imgCompress(file, this.compressLevel);

                    ImageCodecInfo[] icf = ImageCodecInfo.GetImageEncoders();
                    EncoderParameters encps = new EncoderParameters(1);
                    EncoderParameter encp = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 90);
                    encps.Param[0] = encp;

                    fileName = fileName.Substring(0, fileName.LastIndexOf(".")) + ".jpg";


                    img.Save(Path.Combine(path, fileName), icf[1], encps);

                }
                else
                {
                    file.SaveAs(Path.Combine(path, fileName));
                }
            }
            catch(Exception e)
            {
                return "error|文件创建失败!";
            }

            //创建缩略图
            MakeThumbnail(path, fileName);

            //return @"ok|/" + pathBase + "/" + fileName + "|/" + pathBase + "/s" + fileName;
            return fileName;

        }

        /// <summary>
        /// 多个图片文件带缩略图存储
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public string[] imageSave(HttpFileCollectionBase files,Boolean compress = false)
        {

            string[] reInfo = new string[files.Count];

            for (int i = 0; i < files.Count; i++)
            {
                reInfo[i] = imageSave(files[i], compress);
            }
            return reInfo;
            
        }

        /// <summary>
        /// 文件验证 指明文件是否不能上传
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public bool fileValidate(HttpPostedFileBase file)
        {
            if (!HasFile(file)) return false;
            if (fileExts == "") return true;

            string[] ExtArr = fileExts.Split('|');

            foreach (string Ext in ExtArr)
            {
                if (Path.GetExtension(file.FileName).ToLower() == "." + Ext.ToLower()) return true;
            }

            return false;
        }

        //检测文件
        private bool HasFile(HttpPostedFileBase file)
        {
            return (file != null && file.ContentLength > 0) ? true : false;

        }

        //生成日期随机文件名
        private string makeFileName()
        {
            string dateName = DateTime.Now.ToString("yyyyMMddHHmmss");
            string Guid = System.Guid.NewGuid().ToString().Split('-')[1];
            return dateName + Guid;
        }

        /// <summary>
        /// 创建目录并返回完全路径
        /// </summary>
        /// <param name="path"></param>
        private string createPath(string path)
        {
            path = AppDomain.CurrentDomain.BaseDirectory + path;
            if (Directory.Exists(path)) return path;


            try
            {
                Directory.CreateDirectory(path);
            }
            catch
            {
                return AppDomain.CurrentDomain.BaseDirectory + "upload/";
            }

            return path;

        }
        private string createThumbPath(string path)
        {
            path = Path.Combine(path, "s");
            if (Directory.Exists(path)) return path;

            Directory.CreateDirectory(path);

            return path;
        }

        /// <summary>
        /// 图片大小及质量压缩，根据this.compressLevel大小 //保留 未完成
        /// </summary>
        private Image imgCompress(HttpPostedFileBase file, long cLevel, string resize = null)
        {
            Image img = Image.FromStream(file.InputStream);
            //处理最大宽高的限制缩放
            resize = resize ?? this.imageResize;
            int _w=0, _h=0;
            try
            {
                string[] wh = resize.Split('*');
                _w = Convert.ToInt32(wh[0]);
                _h = Convert.ToInt32(wh[1]);
            }
            catch {
                new Exception("请正确设置指定宽高的值");
            }
            int toW = img.Width, toH = img.Height;

            if(img.Width>_w){
                toW = _w;
                toH = img.Height*toW/img.Width;
            }

            if(img.Height>_h){
                toH = _h;
                toW = img.Width*toH/img.Height;
            }
                //新建一个bmp图片
                Image bitmap = new System.Drawing.Bitmap(toW, toH);

                //新建一个画板
                Graphics g = System.Drawing.Graphics.FromImage(bitmap);

                //设置高质量插值法
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

                //设置高质量,低速度呈现平滑程度
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                //清空画布并以透明背景色填充
                g.Clear(Color.Transparent);

                //在指定位置并且按指定大小绘制原图片的指定部分
                g.DrawImage(img, new Rectangle(0, 0, toW, toH),
                    new Rectangle(0, 0, img.Width, img.Height),
                    GraphicsUnit.Pixel);

                
                return bitmap;
        }
        /// <summary>
        /// 根据原图判断是否需要缩略
        /// </summary>
        /// <param name="path">原图path</param>
        /// <returns>是否应该缩放</returns>
        private bool thumbnailSizeFilter(string path)
        {
            Image originalImage = Image.FromFile(path);
            int ow = originalImage.Width;
            int oh = originalImage.Height;
            originalImage.Dispose();

            if (Path.GetExtension(path) != ".jpg" || Path.GetExtension(path) != ".jpeg") return false;
            if (ow <= thumbnailwidth && oh < thumbnailheight) return false;
            if (ow < thumbnailwidth && oh <= thumbnailheight) return false;
            return true;

        }


        /// <summary>
        /// 在图片当前目录下生成缩略图 名字前缀"s" 例子 XXXX.jpg => sXXXX.jpg
        /// </summary>
        /// <param name="originalImagePath">源图路径（物理路径）</param>
        public void MakeThumbnail(string path, string fileName)
        {
            //string pathAll = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory) + path;
            string pathAll = Path.Combine(path, fileName);

            string originalImagePath = pathAll;
            //string thumbnailFileName = "/s" + Path.GetFileNameWithoutExtension(path) + ".jpg";
            string thumbnailFileName = fileName + ".jpg";

            string thumbnailPath = Path.Combine(this.createThumbPath(path), thumbnailFileName);

            Image originalImage = Image.FromFile(originalImagePath);
            getWH(this.thumbnailSize);

            int towidth = thumbnailwidth;
            int toheight = thumbnailheight;

            int x = 0;
            int y = 0;
            int ow = originalImage.Width;
            int oh = originalImage.Height;

            if (thumbnailSizeFilter(pathAll))
            {
                //啥也不干直接copy
                FileInfo fs = new FileInfo(pathAll);
                fs.CopyTo(thumbnailPath);
                return;
            }


            switch (thumbnailMode)
            {

                case "HW"://指定高宽缩放（可能变形）                
                    break;
                case "W"://指定宽，高按比例                    
                    toheight = originalImage.Height * thumbnailwidth / originalImage.Width;
                    break;
                case "H"://指定高，宽按比例
                    towidth = originalImage.Width * thumbnailheight / originalImage.Height;
                    break;
                case "Cut"://指定高宽裁减（不变形）                
                    if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
                    {
                        oh = originalImage.Height;
                        ow = originalImage.Height * towidth / toheight;
                        y = 0;
                        x = (originalImage.Width - ow) / 2;
                    }
                    else
                    {
                        ow = originalImage.Width;
                        oh = originalImage.Width * thumbnailheight / towidth;
                        x = 0;
                        y = (originalImage.Height - oh) / 2;
                    }
                    break;

                default://等比缩放（不变形，如果高大按高，宽大按宽缩放） 
                    if ((double)originalImage.Width / (double)originalImage.Height <= (double)towidth / (double)toheight)
                    {
                        toheight = thumbnailheight;
                        towidth = originalImage.Width * thumbnailheight / originalImage.Height;
                    }
                    else
                    {
                        towidth = thumbnailwidth;
                        toheight = originalImage.Height * thumbnailwidth / originalImage.Width;
                    }
                    break;

            }
            //设置JPG压缩比
            ImageCodecInfo[] icf = ImageCodecInfo.GetImageEncoders();
            EncoderParameters encps = new EncoderParameters(1);
            EncoderParameter encp = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 90);
            encps.Param[0] = encp;

            //新建一个bmp图片
            Image bitmap = new System.Drawing.Bitmap(towidth, toheight);

            //新建一个画板
            Graphics g = System.Drawing.Graphics.FromImage(bitmap);

            //设置高质量插值法
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;

            //设置高质量,低速度呈现平滑程度
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            //清空画布并以透明背景色填充
            g.Clear(Color.Transparent);

            //在指定位置并且按指定大小绘制原图片的指定部分
            g.DrawImage(originalImage, new Rectangle(0, 0, towidth, toheight),
                new Rectangle(x, y, ow, oh),
                GraphicsUnit.Pixel);

            try
            {
                //以jpg格式保存缩略图

                bitmap.Save(thumbnailPath, icf[1], encps);

            }
            catch (System.Exception e)
            {
                throw e;
            }
            finally
            {
                originalImage.Dispose();
                bitmap.Dispose();
                g.Dispose();
            }
        }

        //得到缩略图宽与高
        private void getWH(string str)
        {

            string[] size = str.Split('*');
            try
            {
                thumbnailwidth = Convert.ToInt16(size[0]);
            }
            catch
            {
                thumbnailwidth = 180;
            }


            try
            {
                thumbnailheight = Convert.ToInt16(size[1]);
            }
            catch
            {
                thumbnailheight = 120;
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="path">针对于站点的绝对路径 如： /Content/uploads/xxxx.jpg</param>
        /// <returns>是否成功</returns>
        public static bool del(string path)
        {
            try
            {
                FileInfo file = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + path);
                file.Delete();
            }
            catch
            {
                return false;
            }





            return true;
        }

        /// <summary>
        /// 删除图片 包括其缩略图
        /// </summary>
        /// <param name="path">针对于站点的绝对路径 如： /Content/uploads/xxxx.jpg</param>
        /// <returns>是否成功</returns>
        public static bool delImage(string path)
        {
            char[] separator = { '/', '\\' };

            string[] spathArr = path.Split(separator);
            spathArr[spathArr.Length - 1] = "s/" + spathArr[spathArr.Length - 1];
            string spath = string.Join("/", spathArr + ".jpg");
            FileInfo file;
            try
            {
                file = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + path);
                file.Delete();

                try
                {
                    file = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + spath);
                    file.Delete();
                }
                catch { }


            }
            catch
            {
                return false;
            }

            return true;
        }


        /// <summary>
        /// 得到文件大小
        /// </summary>
        /// <param name="path">文件路径 相对站点根</param>
        /// <returns>文件大小 单位 K</returns>
        public static long getFileSize(string path)
        {
            FileInfo fi;
            try
            {
                fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + path);
                return fi.Length / 1000;
            }
            catch
            {
                return 0;
            }
        }
    }
}